package top.laoshuzi.common.mvp.factory;

import android.support.annotation.Nullable;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import top.laoshuzi.common.mvp.annotations.BindPresenter;
import top.laoshuzi.common.mvp.annotations.RequiresPresenter;
import top.laoshuzi.common.mvp.presenter.Presenter;
import top.laoshuzi.common.mvp.view.View;

public class ReflectionPresenterFactory implements PresenterFactory {

    private Object object;
    private Class<? extends Presenter>[] presenterClasses;
    private List<Field> presenterFields;

    @Nullable
    public static ReflectionPresenterFactory fromViewClass(Object viewObject) {
        RequiresPresenter annotation = viewObject.getClass().getAnnotation(RequiresPresenter.class);
        Class<? extends Presenter>[] classes = null != annotation ? annotation.value() : null;
        if (null == classes) {
            return null;
        }

        List<Field> fields = new ArrayList<>();
        Class tempClass = viewObject.getClass();
        while (tempClass != null && View.class.isAssignableFrom(tempClass)) {
            for (Field field : tempClass.getDeclaredFields()) {
                Annotation[] annotations = field.getDeclaredAnnotations();
                if (annotations.length < 1) {
                    continue;
                }
                if (annotations[0] instanceof BindPresenter) {
                    fields.add(field);
                }
            }
            tempClass = tempClass.getSuperclass();
        }

        return new ReflectionPresenterFactory(viewObject, classes, fields);
    }

    private ReflectionPresenterFactory(Object object, Class<? extends Presenter>[] presenterClasses, List<Field> presenterFields) {
        this.object = object;
        this.presenterClasses = presenterClasses;
        this.presenterFields = presenterFields;
    }

    @Override
    public List<? extends Presenter> createPresenter() {
        try {
            List<Presenter> presenters = new ArrayList<>();
            for (Class<? extends Presenter> presenterClass : presenterClasses) {
                presenters.add(presenterClass.newInstance());
            }
            return presenters;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void bindPresenter(List<? extends Presenter> presenters) {
        for (Field field : presenterFields) {
            String fieldClassName = field.getType().getName();
            for (Presenter presenter : presenters) {
                if (fieldClassName.equals(presenter.getClass().getName())) {
                    try {
                        field.setAccessible(true);
                        field.set(object, presenter);
                    } catch (IllegalAccessException e) {
                        throw new RuntimeException(e);
                    }
                    break;
                }
            }
        }
    }
}
